#Version 1.0
#Creator: Phear The Ceal
#Inital Code: This is a work in progress. Currently it is Emerald just walking around like a player
#6/5/10 12:15 a.m. <Added a gun that does nothing!>
#6/15/10 9:20 p.m. <Added "bombs" that drop powerups and made finished work.>

import pygame, sys, random
from pygame.locals import *

mainClock = pygame.time.Clock()
pygame.init()
WINDOWWIDTH = 256
WINDOWHEIGHT = 256
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))#, pygame.FULLSCREEN)
pygame.display.set_caption('A hero walks')
pygame.mouse.set_visible(False)

class Hero():
    def __init__(self):
        self.hp = 500
        self.ammo = 20
        self.kills = 0
        self.bullets = []
        self.MLeft, self.MRight, self.MUp, self.MDown = False, False, False, False
        self.speed = 2
        self.countAnimate = 0
        self.subCount = 0
        self.dir = 'up'
        
        #set up the images for animation
        self.leftImages = [pygame.image.load('playerL0.PNG'),pygame.image.load('playerL1.PNG'),pygame.image.load('playerL0.PNG'),pygame.image.load('playerL2.PNG')]
        self.rightImages = [pygame.image.load('playerR0.PNG'),pygame.image.load('playerR1.PNG'),pygame.image.load('playerR0.PNG'),pygame.image.load('playerR2.PNG')]
        self.upImages = [pygame.image.load('playerU0.PNG'),pygame.image.load('playerU1.PNG'),pygame.image.load('playerU0.PNG'),pygame.image.load('playerU2.PNG')]
        self.downImages = [pygame.image.load('playerD0.PNG'),pygame.image.load('playerD1.PNG'),pygame.image.load('playerD0.PNG'),pygame.image.load('playerD2.PNG')]
        self.curImage = self.upImages[0]
        #make the white transparent with set_colorkey((255,255,255))
        for group in [self.leftImages, self.rightImages, self.upImages, self.downImages]:
            for sprite in group:
                sprite.set_colorkey((255,255,255))
        
        self.rect = self.curImage.get_rect()
        self.rect.topleft = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2 + 50)
    def check(self, event):
        #this handles all input to the computer
    
        if event.type == KEYDOWN:
            if event.key == K_LEFT or event.key == ord('a'):
                self.MRight = False
                self.MLeft = True
            if event.key == K_RIGHT or event.key == ord('d'):
                self.MLeft = False
                self.MRight = True
            if event.key == K_UP or event.key == ord('w'):
                self.MDown = False
                self.MUp = True
            if event.key == K_DOWN or event.key == ord('s'):
                self.MUp = False
                self.MDown = True
            if event.key == K_SPACE:
                self.shoot(True)
            if event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
                
        if event.type == KEYUP:
            if event.key == K_LEFT or event.key == ord('a'):
                self.MLeft = False
            if event.key == K_RIGHT or event.key == ord('d'):
                self.MRight = False
            if event.key == K_UP or event.key == ord('w'):
                self.MUp = False
            if event.key == K_DOWN or event.key == ord('s'):
                self.MDown = False
                
    def move(self):
        #if you're holding down a key: animate and move! Also, loop from end to end
        blocked = False
        for bomb in Bombs.bombList:
            if bomb['rect'].colliderect(self.rect):
                blocked = True
            
        if self.MLeft and not blocked:
            self.rect.move_ip(-1 * self.speed, 0)
            self.counter()
            if self.rect.right < 0:
                self.rect.left = WINDOWWIDTH
        if self.MRight and not blocked:
            self.rect.move_ip(self.speed, 0)
            self.counter()
            if self.rect.left > WINDOWWIDTH:
                self.rect.right = 0
        if self.MUp and not blocked:
            self.rect.move_ip(0, -1 * self.speed)
            self.counter()
            if self.rect.bottom < 0:
                self.rect.top = WINDOWHEIGHT
        if self.MDown and not blocked:
            self.rect.move_ip(0, self.speed)
            self.counter()
            if self.rect.top > WINDOWHEIGHT:
                self.rect.bottom = 0
            
    def animate(self):
        #decrease health constantly. I know this shouldn't go here but meh
        self.hp -= 2.5
        
        #switches images when moving
        countAnimate = self.countAnimate
        if self.MRight:
            self.curImage = self.rightImages[countAnimate]
            self.dir = 'right'
        elif self.MLeft:
            self.curImage = self.leftImages[countAnimate]
            self.dir = 'left'
        elif self.MUp:
            self.curImage = self.upImages[countAnimate]
            self.dir = 'up'
        elif self.MDown:
            self.curImage = self.downImages[countAnimate]
            self.dir = 'down'
        #swithces images when not moving
        if not self.MRight and self.dir == 'right':
            self.curImage = self.rightImages[0]
        elif not self.MLeft and self.dir == 'left':
            self.curImage = self.leftImages[0]
        elif not self.MUp and self.dir == 'up':
            self.curImage = self.upImages[0]
        elif not self.MDown and self.dir == 'down':
            self.curImage = self.downImages[0]
            
    def counter(self):
        #this is so the animation doesn't go to fast
        self.subCount += 1
        if self.subCount == 10:
            self.countAnimate += 1
            self.subCount = 0
        if self.countAnimate > 3:
            self.countAnimate = 0
    
    def shoot(self, newBullet=False):
        # updates all bullets on the screen and makes new ones
        bullets = self.bullets
        if newBullet and self.ammo > 0:
            self.ammo -= 1
            if self.dir == 'right':
                bullets.append({'rect':pygame.Rect(self.rect.left,self.rect.top,14,19), 'dir':'right'})
            if self.dir == 'left':
                bullets.append({'rect':pygame.Rect(self.rect.left,self.rect.top,14,19), 'dir':'left'})
            if self.dir == 'up':
                bullets.append({'rect':pygame.Rect(self.rect.left,self.rect.top,14,19), 'dir':'up'})
            if self.dir == 'down':
                bullets.append({'rect':pygame.Rect(self.rect.left,self.rect.top,14,19), 'dir':'down'})
        for n in range(len(bullets)):
            n -= 1
            try:
                if bullets[n]['dir'] == 'right':
                    bullets[n]['rect'].move_ip(7,0)
            except IndexError:
                continue
            if bullets[n]['dir'] == 'left':
                bullets[n]['rect'].move_ip(-7,0)
            if bullets[n]['dir'] == 'up':
                bullets[n]['rect'].move_ip(0,-7)
            if bullets[n]['dir'] == 'down':
                bullets[n]['rect'].move_ip(0,7) 
                
            pygame.draw.rect(windowSurface, (255,255,0), bullets[n]['rect'])         
            if bullets[n]['rect'].bottom < 0 or bullets[n]['rect'].right < 0 or bullets[n]['rect'].left > WINDOWWIDTH or bullets[n]['rect'].top > WINDOWHEIGHT:
                bullets.pop(n)
                
class Bomb():
    #this "bomb" will drop powerups and die after 5 hits.
    def __init__(self):
        self.bombList = []
        self.powerupList = []
        self.healthBombImage = pygame.image.load('health.PNG')
        self.ammoBombImage = pygame.image.load('ammo.PNG')
        self.healthBombImage.set_colorkey((255,255,255))
        self.ammoBombImage.set_colorkey((255,255,255))
        self.ammoPowerup = pygame.image.load('ammoPowerup.PNG')
        self.healthPowerup = pygame.image.load('hpPowerup.PNG')
        self.bombRect = self.ammoBombImage.get_rect()
        self.bombHealth = 4
        self.counter = 0
        self.bombList.append({'rect':self.healthBombImage.get_rect(), 'health':self.bombHealth, 'type':'hp', 'image':self.healthBombImage})
        self.bombList[0]['rect'].topleft = (128, 128)
        
    def newBomb(self):
        #you guessed it! Makes a new random bomb
        self.newType = random.choice(['hp', 'ammo'])
        if self.newType == 'hp':
            self.bombList.append({'rect':self.healthBombImage.get_rect(), 'health':self.bombHealth, 'type':self.newType, 'image':self.healthBombImage})
        elif self.newType == 'ammo':
            self.bombList.append({'rect':self.ammoBombImage.get_rect(), 'health':self.bombHealth, 'type':self.newType, 'image':self.ammoBombImage})
        self.bombList[-1]['rect'].topleft = (random.randint(0, WINDOWWIDTH - self.bombRect.width), random.randint(0, WINDOWHEIGHT-self.bombRect.height))
        
        for bomb in range(len(self.bombList)-1):
            if self.bombList[bomb]['rect'].colliderect(self.bombList[-1]['rect']) or Me.rect.colliderect(self.bombList[-1]['rect']):
                del self.bombList[-1]
        
    def update(self):
        #updates all the bombs, deathlist keeps tracks of which ones need to die at the end of the check
        self.deathList = []
        for bomb in range(len(self.bombList[:])):
            for bullet in range(len(Me.bullets[:])):
                bullet -= 1
                if self.bombList[bomb]['rect'].colliderect(Me.bullets[bullet]['rect']):
                    del Me.bullets[bullet]
                    self.bombList[bomb]['health'] -= 1
            if self.bombList[bomb]['health'] < 1:
                self.deathList.append(bomb)
            windowSurface.blit(self.bombList[bomb]['image'], self.bombList[bomb]['rect'])
        for death in self.deathList:
            self.explode(self.deathList)
            del self.bombList[death]
        self.counter += 1
        if self.counter > 100:
            self.newBomb()
            self.counter = 0
        for powerup in self.powerupList:
            windowSurface.blit(powerup['image'], powerup['rect'])
        #also look at all powerups dropped
        self.powerups()
    
    def explode(self, bombs):
        #gets rid of bomb and drops powerup
        for bomb in bombs:
            Me.kills += 1
            if self.bombList[bomb]['type'] == 'hp':
                self.powerupList.append({'rect':self.healthPowerup.get_rect(), 'image':self.healthPowerup, 'type':'hp'})
            if self.bombList[bomb]['type'] == 'ammo':
                self.powerupList.append({'rect':self.ammoPowerup.get_rect(), 'image':self.ammoPowerup, 'type':'ammo'})
            self.powerupList[-1]['rect'].centerx = self.bombList[bomb]['rect'].centerx
            self.powerupList[-1]['rect'].centery = self.bombList[bomb]['rect'].centery
            
    def powerups(self):
        #looks over the powerups for collision with the player
        for powerup in range(len(self.powerupList[:])):
            if self.powerupList[powerup]['rect'].colliderect(Me.rect):
                if self.powerupList[powerup]['type'] == 'ammo':
                    Me.ammo += 7
                if self.powerupList[powerup]['type'] == 'hp':
                    Me.hp += 500
                del self.powerupList[powerup]
            
def drawBG():            
    # tiles one images onto the background
    graphTile = pygame.image.load('dirtTile.PNG')
    graphRect = graphTile.get_rect()
    
    rows = int(WINDOWHEIGHT/graphRect.height) + 1
    columns = int(WINDOWWIDTH/graphRect.width) + 1
    
    for y in range(rows):
       for x in range(columns):
          if x == 0 and y > 0:
             graphRect = graphRect.move(-(columns -1 ) * graphRect.width, graphRect.height)
          if x > 0:
             graphRect = graphRect.move(graphRect.width, 0)
    
          windowSurface.blit(graphTile, graphRect)
          
def drawText(text, surface, x, y, font=pygame.font.SysFont(None, 12)):  
     textobj = font.render(text, 1, (255,255,255))  
     textrect = textobj.get_rect()  
     textrect.topleft = (x, y)  
     surface.blit(textobj, textrect) 
    
def checkForQuit(event):
    #checks if X (close) button is clicked
    if event.type == QUIT:
        pygame.quit()
        sys.exit()
     
Me = Hero()
Bombs = Bomb()
pygame.mixer.music.load('background.mid')  
pygame.mixer.music.play(-1, 0.0)

while True:
    drawBG()
    drawText(("HP: " + str(Me.hp) + " AMMO: " + str(Me.ammo) + " KILLS: " + str(Me.kills)), windowSurface, 0, 0)
    
    if Me.hp < 1 or Me.ammo < 1:
        #checks if you've lost
        while True:
            drawText('YOU LOSE!', windowSurface, 60, 100, font=pygame.font.SysFont(None, 48))
            for event in pygame.event.get():
                checkForQuit(event)
            pygame.display.update()
            
    Bombs.update()
    
    for event in pygame.event.get():
        Me.check(event)
        checkForQuit(event)
        
    Me.move()
    Me.animate()
    Me.shoot()
    
    windowSurface.blit(Me.curImage, Me.rect)
    pygame.display.update()
    mainClock.tick(40)
    
# OVER 300 LINES OF SHIH-TZU!!!